package ar.com.logic.components;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Vector;

import ar.com.logic.components.interfaces.IMatrizPosiciones;

public class MatrizPosiciones implements IMatrizPosiciones {
	private Map<Integer, Posiciones> matrizValores;
	private Map<Integer, Posiciones> matrizPosiciones;
	private Integer maxPosiciones;
	private Integer maxDigitos;
	private CoordenadasFijos conocidos;
	

	public MatrizPosiciones(Boolean incluyeCero, Integer maxPosiciones) {
		this.maxDigitos = 9;
		matrizValores = new HashMap<Integer, Posiciones>();
		matrizPosiciones = new HashMap<Integer, Posiciones>();
		conocidos = new CoordenadasFijos();
		for (int i = 1; i < 10; i++) {
			matrizValores.put(i, new Posiciones(maxPosiciones,false));
		}
		if(incluyeCero){
			matrizValores.put(0, new Posiciones(maxPosiciones,false));
			maxDigitos++;
		}
		
		for (int i = 1; i <= maxPosiciones; i++) {
			matrizPosiciones.put(i, new Posiciones(maxDigitos,true));
		}
		this.maxPosiciones = maxPosiciones;
	
	}
	
	
	public void descartarValor(Integer valor){
		
		for (Integer posicion : this.matrizValores.get(valor).getDisponibles()) {
			matrizPosiciones.get(posicion).descartar(valor);	
		}
		this.matrizValores.get(valor).descartar();
		
	}
	
	public List<Integer> valoresDisponiblesParaPosicion(Integer posicion){
		return this.matrizPosiciones.get(posicion).getDisponibles();
		
	}
	
	public List<Integer> posicionesDisponiblesParaValor(Integer valor){
		return this.matrizValores.get(valor).getDisponibles();
	}
	
	public void descartarPosicionParaValor(Integer valor, Integer posicion){
		this.matrizValores.get(valor).descartar(posicion);
		this.matrizPosiciones.get(posicion).descartar(valor);
	}
	
	public boolean esConocido(Integer valor){
		return this.conocidos.tienePosicionFijaElValor(valor);
	}
	
	public void agregarAConocidos(Integer valor, Integer posicion){
		this.conocidos.agregarCoordenada(valor, posicion);
	}
	public void fijarValorParaPosicion(Integer valor, Integer posicion){
		this.matrizPosiciones.get(posicion).setPosicionUnica(valor);
		for (Entry<Integer, Posiciones> valores : matrizValores.entrySet()) {
			if(valores.getKey()!= valor){
				valores.getValue().descartar(posicion);
			}else{
				valores.getValue().setPosicionUnica(posicion);
			}
		}
		conocidos.agregarCoordenada(valor, posicion);
	}


	public List<Integer> obtenerDescartados() {
		List<Integer> descartados = new Vector<Integer>();
		for (Entry<Integer, Posiciones> es : matrizValores.entrySet()) {
			if(!es.getValue().hasPosicionesDisponibles()){
				descartados.add(es.getKey());
			}
		}
		return descartados;
	
	}
	
	public CoordenadasFijos obtenerFijos(){
		CoordenadasFijos resultado = new CoordenadasFijos();
		for (Entry<Integer, Posiciones> es : matrizValores.entrySet()) {
			if(es.getValue().hasPosicionUnica() 
					&& valoresDisponiblesParaPosicion(es.getValue().getPosicionUnica()).size() == 1){
				resultado.agregarCoordenada(es.getKey(), es.getValue().getPosicionUnica());
			}
		}
		return resultado;
	}


	public Integer getMaxPosiciones() {
		return maxPosiciones;
	}


	public Integer getMaxDigitos() {
		return maxDigitos;
	}


	@Override
	public String toString() {

		String s = "Matriz Posiciones: \n";
		for (Entry<Integer, Posiciones> entry : matrizValores.entrySet()){
			s += "Valor: " + entry.getKey() + ", Posiciones Disponibles: " + entry.getValue() + "\n"; 
		}
		
		return s;
	}


	public List<Integer> obtenerDisponibles() {
		List<Integer> disponibles = new Vector<Integer>();
		for (Entry<Integer, Posiciones> es : matrizValores.entrySet()) {
			if(es.getValue().hasPosicionesDisponibles()){
				disponibles.add(es.getKey());
			}
		}
		return disponibles;
	}


	public CoordenadasFijos obtenerValoresConPosicionUnica() {
		CoordenadasFijos resultado = new CoordenadasFijos();
		for (Entry<Integer, Posiciones> es : matrizValores.entrySet()) {
			if(es.getValue().hasPosicionUnica() && !esConocido(es.getKey())){
				resultado.agregarCoordenada(es.getKey(), es.getValue().getPosicionUnica());
			}
		}
		return resultado;
	}


	
	
	
	
	

}
